﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using BookLibrary.Core.Extensions;
using BookLibrary.Core.ServiceBus;
using BookLibrary.Domain.Exceptions;
using BookLibrary.Events.BookLibraryProcess;

namespace BookLibrary.Domain.BorrowedProcess
{
    public partial class BookLibraryProcess
    {
        public static BookLibraryProcess StartNewProcess(Guid userId)
        {
            return new BookLibraryProcess(userId);
        }

        public void BorrowBook(Book.Book book,TimeSpan borrowInterval)
        {
            Contract.Requires(book != null);
            Contract.Requires(borrowInterval >= TimeSpan.FromDays(1), "borrowInterval>TimeSpan.FromDays(1)");

            if (BookBorrowedRecords.Any(x=>x.Book.ISBN==book.ISBN))
            {
                throw new BorrowSameBookTwiceException($"already have borrowed record for book:{book.Name}");
            }

            var record = new BorrowedRecord(this,UserId, book, borrowInterval);
            BookBorrowedRecords.Add(record);

            var bookRecord = new BookLibraryProcessEvent.BorrowedRecord(UserId, new BookLibraryProcessEvent.Book(record.Book.Id, record.Book.Name), record.BorrowedDate, record.BorrowedInterval);
            EventRaiser.RaiseEvent(new BookLibraryProcessEvent.BookLibraryProcessBookBorrowedEvent(bookLibraryProcessId: Id, borrowedRecord: bookRecord));
        }

        public void ReturnBook(Book.Book book)
        {
            Contract.Requires(book != null, "book!=null");

            if (BookBorrowedRecords.None(x => x.Book.ISBN == book.ISBN))
            {
                throw new DomainException($"Did not borrow this book:{book.Name}");
            }

            var borrowRecord = BookBorrowedRecords.Single(x => x.Book.Id == book.Id&&!x.IsReturn);
            borrowRecord.Return();

            var record = new ReturnedRecord(this, UserId, book, borrowRecord);
            BookReturnedRecords.Add(record);

            var returnRecord=new BookLibraryProcessEvent.ReturnedRecord(UserId,book.Id, record.ReturnDate,record.IsPostpone,record.PostponeDate);
            EventRaiser.RaiseEvent(new BookLibraryProcessEvent.BookLibraryProcessBookReturnedEvent(Id,returnRecord));
        }
    }
}